#include "ciusocket.h"
#include "binarystreamwriter.h"
#include "Msg.h"
#include "ZlibUtil.h"
#include "cminibuffer.h"
#include "binarystreamreader.h"
#include <QHostAddress>
#include <QDebug>

//包最大字节数限制为10M
#define MAX_PACKAGE_SIZE    10 * 1024 * 1024

CIUSocket::CIUSocket()
{
	m_Socket = new QTcpSocket;				//一般用途Socket（非阻塞socket）
    //m_FileSocket;			//传文件的Socket（阻塞socket）
    //m_ImgSocket;
    //connect(m_Socket, &QTcpSocket::connected, this, onConnected());
    //connect(m_Socket, &QTcpSocket::connected, this, onDisConnectd());
    //connect(m_Socket, QTcpSocket::readyRead(), this, );
}


CIUSocket::~CIUSocket()
{

}

CIUSocket& CIUSocket::GetInstance()
{
    static CIUSocket socketInstance;
    return socketInstance;
}

//void CIUSocket::SetRecvMsgThread(CRecvMsgThread* pThread)
//{
//    m_pRecvMsgThread = pThread;
//}

bool CIUSocket::Init()
{
    m_bStop = true;
   // if(!m_spSendThread) {
   //     m_spSendThread.reset(new std::thread(std::bind(&CIUSocket::SendThreadProc, this)));
   // }
   // if (!m_spRecvThread)
   //     m_spRecvThread.reset(new std::thread(std::bind(&CIUSocket::RecvThreadProc, this)));

    return true;
}

void CIUSocket::Uninit()
{
    m_bStop = true;
    //if (m_spSendThread)
    //    m_spSendThread->detach();
    //if (m_spRecvThread)
   //     m_spRecvThread->detach();

   // m_cvSendBuf.notify_one();
   // m_cvRecvBuf.notify_one();

    //如果线程退掉了，这里指针会自动为空，所以再次reset()时先判断一下
    //if (m_spSendThread)
     //   m_spSendThread.reset();
    //if (m_spRecvThread)
    //    m_spRecvThread.reset();

   // CloseFileServerConnection();
   // CloseImgServerConnection();
}

void CIUSocket::Join()
{
    //if (m_spSendThread && m_spSendThread->joinable())
    //    m_spSendThread->join();
    //if (m_spRecvThread && m_spRecvThread->joinable())
    //    m_spRecvThread->join();
}

void CIUSocket::LoadConfig()
{

}

void CIUSocket::SetServer(QString strServer)
{
    m_strServer = strServer.toStdString();
    //Close();
}

void CIUSocket::SetFileServer(QString strFileServer)
{
    // 暂时不用写
}

void CIUSocket::SetImgServer(QString strImgServer)
{
    // 暂时不写
}

void CIUSocket::SetProxyServer(QString strProxyServer)
{
    // 暂时不写
}

void CIUSocket::SetPort(short nPort)
{
    m_nPort = nPort;
    //CloseFileServerConnection();
}

void CIUSocket::SetFilePort(short nFilePort)
{
    //
}

void CIUSocket::SetImgPort(short nImgPort)
{
    //
}

//暂且没用到
void CIUSocket::SetProxyPort(short nProxyPort)
{
    //
}

//暂且没用到
void CIUSocket::SetProxyType(long nProxyType)
{
    //
}

void CIUSocket::EnableReconnect(bool bEnable)
{
    m_bEnableReconnect = bEnable;
}

bool CIUSocket::Connect(int timeout /*=3*/)
{
    //Close();
    m_Socket->connectToHost(QHostAddress("127.0.0.1"), 20000);
    if(m_Socket->state() == QTcpSocket::UnconnectedState) {
        qDebug()<<"Connect Failed";
        return false;
    }
    m_bConnected = true;
    return true;
}


bool CIUSocket::SendData(const char* pBuffer, int nBuffSize, int nTimeout)
{
    int64_t nStartTime = time(NULL);
    int nSentBytes = 0;
    int nRet = m_Socket->write(pBuffer, nBuffSize);
    if(nRet >= nBuffSize) {
        return true;
    }
    return false;
}


bool CIUSocket::RecvData(char* pszBuff, int nBufferSize, int nTimeout)
{
    int64_t nStartTime = time(NULL);
    int nRecvByted = 0;
    int nBytesToRecev = nBufferSize;
    nRecvByted = m_Socket->read(pszBuff, nBufferSize);
    if(nRecvByted>=nBytesToRecev) {
        return true;
    }
    return false;
}

bool CIUSocket::Login(const char* pszUser, const char* pszPassword, int nClientType, int nOnlineStatus, int nTimeout, std::string& strReturnData)
{
    if(!Connect()) {
        return false;
    }

    char szLoginInfo[256] = { 0 };
    sprintf(szLoginInfo,
            "{\"username\": \"%s\", \"password\": \"%s\", \"clienttype\": %d, \"status\": %d}",
            pszUser,
            pszPassword,
            nClientType,
            nOnlineStatus);
    std::string outbuf;
    net::BinaryStreamWriter writeStream(&outbuf);
    writeStream.WriteInt32(msg_type_login);
    writeStream.WriteInt32(0);
    writeStream.WriteCString(szLoginInfo, strlen(szLoginInfo));
    writeStream.Flush();

    std::string strDestBuf;
    if(!ZlibUtil::CompressBuf(outbuf, strDestBuf)) {
        qDebug()<< "compress error";
    }
    msg header;
    memset(&header, 0, sizeof(header));
    header.compressflag = 1;
    header.originsize = outbuf.length();
    header.compresssize = strDestBuf.length();

    std::string strSendBuf;
    strSendBuf.append((const char*)&header, sizeof(header));
    strSendBuf.append(strDestBuf);



    //超时时间设置为3秒
    if (!SendData(strSendBuf.c_str(), strSendBuf.length(), nTimeout)) {
        return false;
    }
    memset(&header, 0, sizeof(header));
    if (!RecvData((char*)&header, sizeof(header), nTimeout)) {
        return false;
    }

    std::string strData;
    if (header.compressflag == PACKAGE_COMPRESSED)
    {
        if (header.compresssize >= MAX_PACKAGE_SIZE || header.compresssize <= 0 ||
            header.originsize >= MAX_PACKAGE_SIZE || header.originsize <= 0)
        {
            Close();
            //LOG_ERROR("Recv a illegal package, compresssize: %d, originsize=%d.", header.compresssize, header.originsize);
            return false;
        }

        CMiniBuffer minBuff(header.compresssize);
        if (!RecvData(minBuff.GetBuffer(), header.compresssize, nTimeout))
        {
            return false;
        }

        std::string strOrigin(minBuff.GetBuffer(), header.compresssize);

        std::string strUncompressBuf;
        if (!ZlibUtil::UncompressBuf(strOrigin, strUncompressBuf, header.originsize))
        {
            Close();
            //LOG_ERROR("uncompress error");
            return false;
        }

        strData = strUncompressBuf;
    }
    else
    {
        if (header.originsize >= MAX_PACKAGE_SIZE || header.originsize <= 0)
        {
            Close();
            // LOG_ERROR("Recv a illegal package, originsize=%d.", header.originsize);
            return false;
        }

        CMiniBuffer minBuff(header.originsize);
        if (!RecvData(minBuff.GetBuffer(), header.originsize, nTimeout))
        {
            return false;
        }
        strData.append(minBuff.GetBuffer(), header.originsize);
    }

    net::BinaryStreamReader readStream(strData.c_str(), strData.length());
    int32_t cmd;
    if (!readStream.ReadInt32(cmd))
        return false;

    int32_t seq;
    if (!readStream.ReadInt32(seq))
        return false;

    size_t datalength;
    if (!readStream.ReadString(&strReturnData, 0, datalength))
    {
        return false;
    }

    return true;
}
void CIUSocket::Close()
{
    //
    //m_Socket->dis
    m_bConnected = false;
}

void CIUSocket::ReceiveMessage()
{

}


void CIUSocket::onConnected()
{
   m_bConnected = true;
}
void CIUSocket::onDisConnectd()
{
     m_bConnected = false;
}
